import 'dart:async';
import 'dart:math';

import 'package:acgn_pioneer/widgets/reader/events/_index.dart';
import 'package:acgn_pioneer/widgets/reader/mixins/_index.dart';
import 'package:flutter/material.dart';

import '../../../../public.dart';
import 'barrage_controller.dart';

typedef BarrageTransitionComplete = void Function();
typedef BarrageTransitionVisible = void Function();
typedef BarrageTransitionDispose = void Function();

/// 弹幕移动
class BarrageTransitionItem extends StatefulWidget {
  final Widget child;
  final BarrageWidgetChannel channel; // 通道信息
  final double postionTop; // 距离布局头部top
  final BarrageTransitionComplete complete; // 动画完全离开视窗回调
  final BarrageTransitionVisible visible; // 动画完全进入视窗时回调
  final BarrageTransitionDispose dispose; // 动画被回收

  const BarrageTransitionItem(
      {Key key,
      @required this.child,
      this.channel,
      this.postionTop = 0,
      this.complete,
      this.dispose,
      this.visible})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => BarrageTransitionItemState();
}

class BarrageTransitionItemState extends State<BarrageTransitionItem>
    with TickerProviderStateMixin, ReaderWidgetBase {
  Random random = new Random();
  AnimationController animationController;
  Animation<double> animation;
  var subScroll; // 滑动事件
  var subScrollEnd; // 滑动结束事件
  bool isNormalDispose = false; // 是否正常结束

  @override
  void initState() {
    super.initState();

    animationController = AnimationController(
        duration: Duration(
            milliseconds:
                barrageSetting.duration + widget.channel.durationOffset),
        vsync: this);
    animation = new Tween<double>(begin: 0, end: readModel.screenWidth * 2)
        .animate(animationController..forward());

    subScroll = readerPage.bus.on<ReaderMoveEvent>().listen((event) {
      if (animationController.isAnimating) {
        animationController.stop();
      }
    });
    subScrollEnd = readerPage.bus.on<ReaderMoveEndEvent>().listen((event) {
      animationController.forward();
    });
  }

  BarrageSetting get barrageSetting {
    return readerPage.barrageController.barrageSetting;
  }

  @override
  Widget build(BuildContext context) {
    final fixedWidth = readModel.screenWidth + random.nextInt(20).toDouble();
    var perPadding = barrageSetting.channelPadding / 2;
    var tempWidth = fixedWidth;
    var visibleNotify = false;
    return AnimatedBuilder(
        animation: animation,
        child: widget.child,
        builder: (BuildContext context, Widget child) {
          // 兜底动画完成
          if (animation.isCompleted) {
            return closeAnimation();
          }

          RenderBox box = context.findRenderObject();
          if (box != null && RenderObject.debugActiveLayout == null) {
            // 判断是否完全进入视窗
            if (fixedWidth - tempWidth > box.size.width && !visibleNotify) {
              visibleNotify = true;
              Timer(Duration(milliseconds: 100), () {
                widget.visible();
              });
            }

            // 判断是否完全移出了视窗
            if (tempWidth.abs() > (fixedWidth + box.size.width)) {
              return closeAnimation();
            }
          }

          var speed = barrageSetting.speed == 0 ? 1 : barrageSetting.speed;
          tempWidth = tempWidth - animation.value * (1 + speed / 100);
          return Transform.translate(
              offset: Offset(tempWidth, widget.postionTop),
              child: Opacity(
                  opacity: 0.3 + 0.7 * barrageSetting.opacity / 100,
                  child: Container(
                      padding:
                          EdgeInsets.only(top: perPadding, bottom: perPadding),
                      child: child)));
        });
  }

  // 关闭动画
  Widget closeAnimation() {
    animationController.dispose();
    Timer(Duration(milliseconds: 100), () {
      widget.complete();
    });
    isNormalDispose = true;
    return SizedBox.shrink();
  }

  @override
  void dispose() {
    super.dispose();
    subScroll.cancel();
    subScrollEnd.cancel();
    if (!isNormalDispose) {
      widget.dispose();
    }
  }
}
